var topPlayers = {}; 
/* uid: { 
    timer : 0,  // 上次更新玩家武将信息的时间
    roles : {},
    'equips' : {},
    'role_attrs': {}
}*/

function Rank(){
    this.ai = 0;
    this.ranks = {};        // rank:uid
    this.rewardRanks = {};  // 领奖排名 uid:rank
    this.rewardDay = 0;     // 更新领奖排名日期

    this.users = {};        // uid:rank
    this.top3 = [];         // 前三
    this.top3Update = 0;    // 前三更新
    this.prisonMatchCursors = {};   // 监狱匹配Cursor
    this.messages = {}; /*
                            uid : [{
                                name:'',     侵略者或防守者名字
                                time:0,      侵略时间
                                succ:0,      侵略成功标志
                                flag:0,      0标志位侵略者名字,1标志为防守者名字
                                rank:0,      玩家当前名次
                                replay:0,    回放id
                                type:'',     rank
                                headpic:''   侵略者或防守者的头像 
                            }]
                        */
    this.updates = {};
}

Rank.create = function() {
    gDBWorld.insert({_id:'rank', ai:0, rank:{}, reward_rank:{}, reward_day:0}, function(err, result){});
};

Rank.prototype = {
    init : function(callback) {

        // 读取排行榜数据
        gDBWorld.findOne({_id : 'rank'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                this.ai = doc.ai;
                this.rewardRanks = doc.reward_rank;
                this.rewardDay = doc.reward_day;
                this._init(callback);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    _init : function(callback) {
        // 检查rank正确性
        var needSave = false;
        var newRank = [];
        var existRanks = {};
        for( var i=1; i<=this.ai; i++ ) {
            var uid = +this.ranks[i];
            if( !uid ) {
                continue;
            }

            var existRank = existRanks[uid];
            if( existRank ) {
                continue;
            }else{
                existRanks[uid] = i;
            }

            newRank.push(uid);
        }

        if( newRank.length != this.ai ) {
            ERROR('RANK reconstruct');

            needSave = true;
            this.ranks = {};
            this.ai = newRank.length;
            for( var i=0; i<newRank.length; i++ ) {
                this.ranks[i+1] = newRank[i];
            }
        }

        for( var rank in this.ranks ) {
            this.users[this.ranks[rank]] = +rank;
        }

        // 检查新增加字段
        if( !this.rewardRanks ) {
            this.rewardRanks = {};
            this.rewardDay = 0;
            needSave = true;
        }

        if( needSave ) {
            this.saveAll(callback);
        }else{
            callback && callback(true);
        }
    },

    markDirty : function(rank) {
        this.updates[rank] = 1;
    },

    save : function(force, callback) {
        if( !force && Object.keys(this.updates).length <= 10) {
            callback && callback(true);
            return;
        }
        
        var updates = {'ai':this.ai};
        for( var rank in this.updates ) {
            var uid = this.ranks[rank];
            updates['rank.'+rank] = uid;
        }
        this.updates = {};
        
        gDBWorld.update({_id : 'rank'}, {$set:updates}, function(err, result){
            if( err ) {
                ERROR(util.format('SAVE RANK: %j %j', updates, err));
                callback && callback(false);
            }else {
                LOG(util.format('SAVE RANK: %j', updates));
                callback && callback(true);
            }
        });
    },

    saveAll : function(callback){
        this.updates = {};
        var rankDocument = {
            '_id': 'rank', 
            'ai': this.ai,
            'rank': this.ranks, 
            'reward_rank': this.rewardRanks,
            'reward_day': this.rewardDay
        };

        gDBWorld.save(rankDocument, function(err, result){
            if( err ) {
                ERROR(util.format('SAVE FULL RANK: %j %j', rankDocument, err));
                callback && callback(false);
            }else {
                callback && callback(true);
            }
        });
    },

    addRank : function(uid, player) {
        this.ai += 1;
        var rank = this.ai;
        this.updateRank(rank, player);

        return rank;
    },

    swapRank : function(uid1, uid2) {
        //uid1为自己，uid2为对手
        var rank1 = this.getRank(uid1);
        var rank2 = this.getRank(uid2);

        if( rank1 < rank2 ) {
            // 挑战比自己排名低的玩家,排名不变
            return false;
        }

        this.ranks[rank2] = uid1;
        this.ranks[rank1] = uid2;

        this.users[uid2] = rank1;
        this.users[uid1] = rank2;

        this.markDirty(rank1);
        this.markDirty(rank2);

        return true;
    },

    getRank : function(uid) {
        var rank = this.users[uid];
        if( !rank ) {
            this.ai += 1;
            rank = this.ai;
            this.users[uid] = rank;
            this.ranks[rank] = uid;

            this.markDirty(rank);
        }

        return rank;
    },

    getMatchFighters : function(uid) { 
        var rank = this.getRank(uid);

        var factorN = 1;
        if( rank > 5000 ) {
            factorN = 500;
        }else if( rank > 2000 ) {
            factorN = 100;
        }else if( rank > 800 ) {
            factorN = 10; 
        }else if( rank > 400 ) {
            factorN = 5;
        }else if( rank > 100 ) {
            factorN = 3;
        }
        
        var matchRanks = [];
        if( rank <= 6 ) {
            for( var i=6; i>0; i-- ) {
                if( i == rank ) {
                    continue;
                }
                matchRanks.push(i);
            }
        }else{
            for( var i=1; i<=5; i++ ) {
                matchRanks.push( rank - i*factorN); 
            }
        }
        
        var matches = [];
        for( var i=0,max=matchRanks.length; i<max; i++ ) {
            var matchRank = matchRanks[i];
            var matchUid = this.ranks[matchRank];
            if( !matchUid ) {
                continue;
            }

            matches.push([matchRank, gUserInfo.getUser(matchUid), matchUid]);
        }

        return matches;
    },

    getRewardRank : function(uid) {
        return this.rewardRanks[uid] || 0;
    },

    updateRewardRanks : function(force) {
        var today = common.getDate();
        if( !force ) {
            if( today == this.rewardDay ) return;

            var todayDate = new Date();
            var todaySeconds = todayDate.getHours() * 3600 + todayDate.getMinutes() *  60 + todayDate.getSeconds();
            if( this.rewardDay && ((todaySeconds + 10) < (gConfGlobal.RankGetRewardTime * 3600)) )  return;
        }

        var rewardRanks = {};
        for( var rank in this.ranks ) {
            rewardRanks[this.ranks[rank]] = +rank;
        }

        this.rewardRanks = rewardRanks;
        this.rewardDay = today;

        this.saveAll();
    },

    //读取排行榜玩家
    getRewardRanks : function() {
        this.updateRewardRanks();
        var ranks = this.rewardRanks;

        var rankEmpty = true;
        for (var rank in ranks) {
            rankEmpty = false;
            break;
        }

        if (rankEmpty) {
            this.updateRewardRanks(true); 
            ranks = this.rewardRanks;
        }

        return ranks;
    },

    getTop3 : function() {
        var now = common.getTime();
        if( (now - this.top3Update) < 60 ) return;

        var top3 = [];
        for( var i=1; i<=3; i++ ) {
            var userUid = gRank.ranks[i];
            if( !userUid ) continue;

            var userData = clone(gUserInfo.getUser(userUid));

            var mainRid = 0;
            var topPlayer = topPlayers[userUid];
            if( topPlayer ) {
                for( var rid in topPlayer.roles ) {
                    if( 5 == gConfRole[rid].ReceiveMode ) {
                        mainRid = rid; 
                        break;
                    }
                } 
            }

            if( !mainRid ) {
                var maxFightForce = 0;
                var roles = userData.roles;
                for( var rid in roles ) {
                    if( 5 == gConfRole[rid].ReceiveMode ) {
                        mainRid = rid; 
                        break;
                    }

                    if( roles[rid] > maxFightForce ) {
                        mainRid = rid;
                        maxFightForce = roles[rid];
                    }
                }
            }
    
            userData.uid = userUid;
            userData.role_god = 0;
            if( topPlayer && mainRid > 0 && topPlayer.roles[mainRid] ) {
                userData.role_god = topPlayer.roles[mainRid].god;
            }

            userData.main_role = mainRid;
            top3.push( userData );
        }

        this.top3 = top3;

        return this.top3;
    },

    getPrisonTarget : function(uid) {
        var rank = this.users[uid] || this.ai;

        var start = rank - 30;
        if( start < 1 ) {
            start = 1;
        }
        var end = rank + 30;
        if( end > this.ai ) {
            end = this.ai;
        }

        var cursor = this.prisonMatchCursors[uid];
        if( !cursor ) {
            cursor = start;
            this.prisonMatchCursors[uid] = cursor;
        }
        
        
        var targets = [];
        var len = end-start+1;
        for( var i=1; i<=len; i++ ) {
            var search = cursor + i;
            if( search > end ) {
                search -= len;
            }
            if( search == rank ) {
                continue;
            }
            
            var targetUid = this.ranks[search];
            var userInfo = gUserInfo.getUser(targetUid);
            targets.push({
                uid: targetUid,
                name: userInfo.name,
                headpic: userInfo.headpic, 
                level: userInfo.level, 
                output: gConfLevel[userInfo.level].PrisonOutPut,
                fight_force: userInfo.fight_force});

            if( targets.length >= 6 ) {
                this.prisonMatchCursors[uid] = search;
                return targets;
            }
        }

        return targets;
    },

    addMessage : function(uid, message){
        var messages = this.getMessage(uid);
        if( messages.length >= gConfGlobal.RankMessageMaxLength ) {
            var expireMessage = messages.shift(); 
            gReplay.deleteReplay(expireMessage.replay);
        }
        messages.push(message);
    },

    getMessage : function(uid) {
        var rankMessage = this.messages[uid];
        if( !rankMessage) {
            rankMessage = [];
            this.messages[uid] = rankMessage;
        }

        return rankMessage;
    },
};

exports.fight = function(req, resp, onHandled) {
    var uid = req.uid;
    do {
        if( isNaN(req.args.rank) || isNaN(req.args.enemy) ) {
            resp.code = 1; resp.desc = 'no valid args'; break;
        }

        var enemy = gRank.ranks[req.args.rank];
        if( !enemy || enemy == uid || enemy != Math.round(req.args.enemy) ) {
            // 数据变化
            resp.data.update = 1; break;
        }

        var selfRank = gRank.getRank(uid);
        var targetRank = +req.args.rank;

        if( targetRank < 20 ){
            if( selfRank > 100 ) {
                resp.code = 1; resp.desc = 'fuck'; break;
            }
        }else{
            if( selfRank < targetRank || selfRank/targetRank > 3 ) {
                resp.code = 1; resp.desc = 'fuck'; break;
            }
        }

    }while(false);

    if( resp.code != 0 || resp.data.update ) {
        onHandled();
        return;
    }

    var rank = +req.args.rank;
    var enemy = gRank.ranks[rank];

    doPVP(uid, enemy, function(battleReport) {
        if( !battleReport ) {
            resp.code = 1; resp.desc = 'pvp error';
            onHandled();
            return;
        }

        var playerInfo = gUserInfo.getUser(uid);
        var enemyInfo = gUserInfo.getUser(enemy);

        var playerName = playerInfo.name;
        var enemyName = enemyInfo.name;

        var playerUid = uid;
        var enemyUid = enemy;

        var success = battleReport.success;
        var rankChange = false;
        if( success ) {
            rankChange = gRank.swapRank(playerUid, enemyUid);
        }

        var attackTime = common.getTime();
        var playerRank = gRank.getRank(playerUid);
        var enemyRank = gRank.getRank(enemyUid);

        // 自己的消息
        var message =  {
            'name' : enemyName, 
            'time' : attackTime, 
            'succ' : success, 
            'flag' : 1, 
            'rank' : rankChange ? playerRank : 0, 
            'replay' : gReplay.addReplay(battleReport),
            'type' : 'rank',
        };
        gRank.addMessage(playerUid, message);
        
        // 对手消息
        message = {
            'name' : playerName, 
            'time' : attackTime, 
            'succ' : success, 
            'flag' : 0, 
            'rank' : rankChange ? enemyRank : 0, 
            'replay' : gReplay.addReplay(battleReport),
            'type' : 'rank',
        };
        gRank.addMessage(enemyUid, message);

        if( success ) {
            message = {
                'uid': playerUid,
                'type' : 'rank',
                'name' : playerName, 
                'time' : attackTime, 
                'succ' : success, 
                'flag' : 0, 
                'rank' : rankChange ? enemyRank : 0, 
                'replay' : gReplay.addReplay(battleReport),
            };
            gMessage.addMessage(enemyUid, message); 
            resp.data.replay = message.replay;
            resp.data.enemy_uid = enemyUid;
        } 

        resp.data.battle = battleReport;
        resp.data.gold = gConfGlobal.RankEachGold;
        resp.data.honor = gConfGlobal.RankEachHonor;

        gRank.save();
        onHandled();
    });
}

exports.get = function(req, resp, onHandled) {
    
    gUserInfo.updateRole(req.uid, req.args.roles, req.args.fight_force);

    var uid = +req.uid;

    gRank.updateRewardRanks();

    resp.data.top3 = gRank.getTop3();
    resp.data.matches = gRank.getMatchFighters(uid);
    resp.data.rank = {
        'rank': gRank.getRank(uid), 
        'reward_rank': gRank.getRewardRank(uid), 
        'reward_day': gRank.rewardDay
    };
    resp.data.messages = gRank.getMessage(uid); 

    gRank.save();
    onHandled();
}

exports.get_reward = function(req, resp, onHandled) {
    do {
        var uid = req.uid;

        gRank.updateRewardRanks();

        resp.data.reward_rank = gRank.getRewardRank(uid);
        resp.data.reward_day = gRank.rewardDay;

    }while(false);

    onHandled();
}

exports.get_top = function(req, resp, onHandled) {

    var topUsers = [];
    var newTopPlayers = {};
    for( var i = 1; i <= 10; i++ ) {
        var userUid = gRank.ranks[i];
        if( !userUid ) continue;

        var userData = clone(gUserInfo.getUser(userUid));
        userData.uid = userUid;

        topUsers.push(userData);

        if( userUid in topPlayers ) {
            newTopPlayers[userUid] = topPlayers[userUid];
        }
    } 
    
    topPlayers = newTopPlayers;

    resp.data= topUsers;
    onHandled();
}

exports.get_user = function(req, resp, onHandled) {

    if( isNaN(req.args.id) ) {
        resp.code = 1; resp.desc = 'no valid args'; 
        onHandled();
        return;
    }

    var userId = req.args.id;
    var rank = gRank.getRank(userId);
    if( rank <= 0 || rank > 50 ) {
        resp.code = 1; resp.desc = 'not in top10'; 
    }

    var now = common.getTime();
    var userData = topPlayers[userId];

    if( userData && (now - userData.timer < 60) ) {
        resp.data.infos = userData;
        onHandled();
        return;
    }

    gPlayers.get(userId, function(player){
        var user = player.user;

        var equips = {};
        var horses = {};
        var roles = user.role;
        var userHorses = user.ride.horse;

        for( var id in roles ) {
            var role = roles[id];
            player.calculateRoleAttr(role);

            ['weapon','armor','accessory'].forEach(function(type){
                var equipId = role[type];
                if( equipId ) {
                    equips[equipId] = user.equip[equipId];
                }
            });

            if (role.ride && role.ride.horse) {
                horses[role.ride.horse] = userHorses[role.ride.horse];    
            }
        }

        topPlayers[userId] = {
            'timer' : now,
            'roles' : roles,
            'equips' : equips,
            'horses' : horses,
            'role_attrs': player.roleAttrs,
            'special_role_name' : user.special_role ? user.special_role.name : '',
            'pet_level' : user.pet ? user.pet.level : 1,
        };

        resp.data.infos = topPlayers[userId];
        onHandled();
    });
}

function TowerRank(){
    this.ranks = null;
}

TowerRank.create = function(){
    var ranks = {
        1: {'uid':0, 'name':'', 'headpic':'', 'floor':0, 'fight_force':0},
        2: {'uid':0, 'name':'', 'headpic':'', 'floor':0, 'fight_force':0},
        3: {'uid':0, 'name':'', 'headpic':'', 'floor':0, 'fight_force':0},
    };
    gDBWorld.insert({_id:'tower_rank', rank:ranks}, function(err, result){}); 
}

TowerRank.prototype = {
    init : function(callback) {
        // 读取排行榜数据
        gDBWorld.findOne({_id: 'tower_rank'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    save : function() {
        gDBWorld.save({_id: 'tower_rank', rank: this.ranks}, function(err, result){});
    },

    update : function(uid, name, headpic, floor, fight_force) {
        var lastRank = this.ranks[3];
        if( floor <= lastRank.floor ) {
            return;
        }

        var existRank = 0;
        for( var i=1; i<=3; i++ ) {
            var rank = this.ranks[i];
            if( rank.uid == uid ) {
                existRank = i;
                break;
            }
        }

        if( existRank ) {
            this.swapRank(existRank, 3); 
            if( 1 == existRank ) {
                this.swapRank(1, 2);     
            }
        }
        
        var lastRank = this.ranks[3];
        lastRank.uid = uid;
        lastRank.name = name;
        lastRank.headpic = headpic;
        lastRank.floor = floor;
        lastRank.fight_force = fight_force;

        for( var i=2; i>=1; i-- ) {
            var rank = this.ranks[i];
            if( floor <= rank.floor ) {
                break;
            }
        }

        var newPos = (i+1);
        // 交换位置
        for( var i=2; i>=newPos; i-- ) {
            this.swapRank(i+1, i);
        }

        this.save();
    },

    swapRank : function(rank1, rank2) {
        if( rank1 == rank2 ) return;

        var swapRank = this.ranks[rank2];
        this.ranks[rank2] = this.ranks[rank1];
        this.ranks[rank1] = swapRank;
    },
};

function TopOne2(){
    this.topone2 = null;
    this.replay = [];
    this.updates = {};

    this.rankRewards = null;
}

TopOne2.create = function(){
    var topone2 = { 
        _id: 'topone2', 
        'reward': 0,        // 是否领取第一名奖励
        'day': 0,           // 开战日期
        'uid': 0,           // 擂主uid
        'win': 0,           // 连胜场次
        'f_rank':[],        // 鲜花排行
        'e_rank':[],        // 鸡蛋排行
        'rank_reward':{},   // 排行奖励领取
        'votes':{           // 投票情况
            /*
            uid: {'f':0, 'e':0}
            */
        },
    };
    gDBWorld.insert(topone2, function(err, result){}); 
}

TopOne2.prototype = {
    init : function(callback) {
        gDBWorld.findOne({_id : 'topone2'}, {}, function(err, doc){
            if( doc ) {
                this.topone2 = doc;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    isActive : function() {
        return findActivitySchedule('crazy');
    },

    isRewarding : function() {
        var activitySchedule = findActivitySchedule('crazy');
        if( !activitySchedule ) return false;

        var day = Math.floor((common.getTime() - activitySchedule.time)/86400);
        var fightStartTime = activitySchedule.time + day * 86400 + gConfGlobal.CrazyRankStartHour * 3600;
        var fightEndTime = activitySchedule.time + day * 86400 + gConfGlobal.CrazyRankEndHour * 3600;

        var now = common.getTime();
        if( now >= fightStartTime && now <= fightEndTime ) {
            return false;
        }

        return true;
    },

    rankReward : function() {
        if( this.rankRewards ) return;
        if( !this.isRewarding() ) return;

        this.rankRewards = {};
        
        ['f', 'e'].forEach(function(type){
            var ranks = this.topone2[type+'_rank'];
            for( var i=1; i<=ranks.length; i++ ) {
                var uid = ranks[i-1].uid;
                var rankReward = this.rankRewards[uid];
                if( !rankReward ) {
                    rankReward = {};
                    this.rankRewards[uid] = rankReward;
                }
                rankReward[type] = i;
            }
        }.bind(this));
    },

    getRankNames : function() {
        var rankNames = {};

        var topone2 = this.topone2;
        ['f', 'e'].forEach(function(type){
            var ranks = topone2[type+'_rank'];
            for( var i=1; i<=ranks.length; i++ ) {
                var uid = ranks[i-1].uid;
                var userInfo = gUserInfo.getUser(uid);
                rankNames[uid] = userInfo.name;
            }
        });
        
        return rankNames;
    },

    getVote : function(uid) {
        var voteData = this.topone2.votes[uid];
        if( !voteData ) {
            voteData = {'f':0, 'e':0};
            this.topone2.votes[uid] = voteData;
        }

        return voteData;
    },

    vote : function(voteType) {
        var voteData = this.getVote(this.topone2.uid);
        voteData[voteType] += 1;

        this.addUpdate('votes.'+this.topone2.uid, voteData);

        return voteData;
    },

    checkUpdate : function() {
        if( this.isRewarding() ) return;

        var activitySchedule = findActivitySchedule('crazy');
        if( !activitySchedule ) {
            return;
        }

        var day = Math.ceil((common.getTime() - activitySchedule.time)/86400);
        if( this.topone2.day == day ) {
            return;
        }

        // 重启开启
        this.topone2.day = day;
        this.topone2.uid = 0;
        this.topone2.win = 0;
        this.topone2.reward = 0;
        this.topone2.f_rank = [];
        this.topone2.e_rank = [];
        this.topone2.rank_reward = {};
        this.topone2.votes = {};

        this.rankRewards = null;
        this.replay = [];

        this.addUpdate('day', this.topone2.day);
        this.addUpdate('uid', this.topone2.uid);
        this.addUpdate('win', this.topone2.win);
        this.addUpdate('reward', this.topone2.reward);
        this.addUpdate('f_rank', this.topone2.f_rank);
        this.addUpdate('e_rank', this.topone2.e_rank);
        this.addUpdate('rank_reward', this.topone2.rank_reward);
        this.addUpdate('votes', this.topone2.votes);
    },

    get : function(uid) {
        var haveRankReward = 0;
        if( this.rankRewards && this.rankRewards[uid] && !this.topone2.rank_reward[uid] ) {
            haveRankReward = 1;
        }

        if( !this.topone2.uid ) {
            // 第一人
            this.topone2.uid = uid;
            this.addUpdate('uid', uid);
        }

        var userInfo = gUserInfo.getUser(this.topone2.uid);
        return {
            'day' : this.topone2.day,
            'uid' : this.topone2.uid,
            'win' : this.topone2.win,
            'replay' : this.replay,
            'name' : userInfo.name,
            'headpic' : userInfo.headpic,
            'fight_force' : userInfo.fight_force,
            'reward' : this.topone2.reward,
            'rank_reward' : haveRankReward,
            'vote': this.getVote(this.topone2.uid),
        };
    },

    addUpdate : function(item, obj) {
        this.updates[item] = obj;
    },

    save : function(callback) {
        if( !this.updates || Object.keys(this.updates).length == 0 ) {
            callback && callback(true);
            return;
        }

        var updates = this.updates;
        gDBWorld.update({_id : 'topone2'}, {$set:updates}, function(err, result){
            if( err ) {
                ERROR({updates:updates, err:err});
                callback && callback(false);
            }else {
                callback && callback(true);
            }
        });

        this.updates = {};
    },
}

exports.get_topone2 = function(req, resp, onHandled){
    do{
        if( !gTopOne2.isActive() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        gTopOne2.checkUpdate();
        gTopOne2.rankReward();

        resp.data.topone2 = gTopOne2.get(req.uid);
        gTopOne2.save();
    }while(false);

    onHandled();
}

exports.challenge_topone2 = function(req, resp, onHandled){
    do{
        if( req.args.day != gTopOne2.topone2.day ) {
            resp.code = 1; resp.desc = 'hack'; break;
        }

        if( !gTopOne2.isActive() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        if( gTopOne2.isRewarding() ) {
            resp.code = 1; resp.desc = 'rewarding'; break;
        }

        gTopOne2.checkUpdate();

        var topone2 = gTopOne2.topone2;
        if( topone2.uid == req.uid ) {
            resp.code = 1; resp.desc = 'fight self'; break;
        }

        doPVP(req.uid, topone2.uid, function(battleReport){
            if( !battleReport ) {
                resp.code = 1; resp.desc = 'pvp error';
                onHandled();
                return;
            }
            
            var success = battleReport.success;
            var message = {
                'atk' : (gUserInfo.getUser(req.uid)).name, 
                'def' : (gUserInfo.getUser(topone2.uid)).name,
                'succ': success, 
                'replay': gReplay.addReplay(battleReport),
            }

            if( success ) {
                gTopOne2.replay = [message]; 
                topone2.uid = req.uid;
                topone2.win = 1;

                gTopOne2.addUpdate('uid', topone2.uid);
                gTopOne2.addUpdate('win', topone2.win);

                resp.data.topone2 = gTopOne2.get();
            }else{
                if( gTopOne2.replay.length > 5 ) {
                    gTopOne2.replay.shift(); 
                }

                gTopOne2.replay.push(message);

                topone2.win += 1;
                gTopOne2.addUpdate('win', topone2.win);
            }

            resp.data.battle = battleReport;

            gTopOne2.save();
            onHandled();
        });
        
        return;
    }while(false);

    onHandled();
}

exports.get_topone2_reward = function(req, resp, onHandled){
    do{
        if( req.args.day != gTopOne2.topone2.day ) {
            resp.code = 1; resp.desc = 'hack'; break;
        }

        if( !gTopOne2.isRewarding() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        var topone2 = gTopOne2.topone2;
        if( topone2.reward ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        if( topone2.uid != req.uid ) {
            resp.code = 1; resp.desc = 'not you'; break;
        }

        topone2.reward = 1;
        gTopOne2.addUpdate('reward', topone2.reward);

        resp.data.reward = 1;
        gTopOne2.save();
    }while(false);

    onHandled();
}

exports.get_topone2_rank = function(req, resp, onHandled){
    do{
        if( req.args.day != gTopOne2.topone2.day ) {
            resp.code = 1; resp.desc = 'hack'; break;
        }

        if( !gTopOne2.isActive() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        var topone2 = gTopOne2.topone2;

        resp.data.f_rank = topone2.f_rank;
        resp.data.e_rank = topone2.e_rank;
        resp.data.vote = gTopOne2.getVote(req.uid);
        resp.data.names = gTopOne2.getRankNames();

    }while(false);

    onHandled();
}

exports.get_topone2_rank_reward = function(req, resp, onHandled){
    do{
        if( req.args.day != gTopOne2.topone2.day ) {
            resp.code = 1; resp.desc = 'hack'; break;
        }

        var uid = req.uid;
        if( !gTopOne2.isRewarding() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        gTopOne2.rankReward();

        var ranks = gTopOne2.rankRewards[uid];
        if( !ranks ) {
            resp.code = 1; resp.desc = 'not in rank'; break;
        }

        var topone2 = gTopOne2.topone2;
        if( topone2.rank_reward[uid] ) {
            resp.code = 1; resp.desc = 'got'; break;
        }

        topone2.rank_reward[req.uid] = 1;
        gTopOne2.addUpdate('rank_reward.'+req.uid, 1);
        gTopOne2.save();

        resp.data.ranks = ranks;

    }while(false);

    onHandled();
}

exports.topone2_vote = function(req, resp, onHandled){
    do{
        if( req.args.day != gTopOne2.day ) {
            resp.code = 1; resp.desc = 'hack'; break;
        }

        if( !gTopOne2.isActive() ) {
            resp.code = 1; resp.desc = 'timeout'; break;
        }

        if( gTopOne2.isRewarding() ) {
            resp.code = 1; resp.desc = 'rewarding'; break;
        }

        var topone2 = gTopOne2.topone2;

        var voteType = req.args.flower ? 'f' : 'e';
        var voteData = gTopOne2.vote(voteType);
        var voteNum = voteData[voteType];
        var voteUid = topone2.uid;

        var rankType = voteType+'_rank';
        var ranks = topone2[rankType];

        if( ranks.length < 5 || voteNum > ranks[ranks.length-1].num ) {
            // 进入排行榜
            var existIndex = -1;
            for( var i=0; i<ranks.length; i++ ) {
                if( ranks[i].uid == voteUid ) {
                    existIndex = i;
                    break;
                }
            }
            
            if( existIndex >= 0 ) {
                ranks.splice(existIndex, 1);
            }
            ranks.push({'uid':voteUid, 'num':voteNum});
            ranks.sort(function(a, b) {
                return b.num - a.num;
            });

            if( ranks.length > 5 ) {
                var rankData = ranks.pop();
            }
            
            gTopOne2.addUpdate(rankType, ranks);
        }

        gTopOne2.save();

    }while(false);

    onHandled();
}

function TowerActivityRank(){
    this.ranks = null;
}

TowerActivityRank.create = function(){
    var ranks = [
        /*{'uid':0, 'name':'', 'headpic':'', 'floor':0, 'got':0, 'time':0},*/
    ];
    gDBWorld.insert({_id:'tower_activity_rank', rank:ranks}, function(err, result){}); 
}

TowerActivityRank.prototype = {
    init : function(callback) {
        // 读取排行榜数据
        gDBWorld.findOne({_id: 'tower_activity_rank'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    save : function() {
        gDBWorld.save({_id: 'tower_activity_rank', rank: this.ranks}, function(err, result){});
    },

    update : function(uid, name, headpic, floor) {
        var now = common.getTime();
        var userRank = {
            'uid' : uid, 
            'name' :name,
            'headpic':headpic,
            'floor':floor,
            'got':0,
            'time' : now, 
        };
        
        var ranks = this.ranks;
        var existRank = 0;
        for( var i=0, len = ranks.length; i<len; i++ ) {
            var rank = ranks[i];
            if( !rank.time ) {
                rank.time = now; 
            }

            if( rank.uid == uid ) {
                existRank = i+1;
            }
        }
        
        if( existRank ) {
            if( ranks[existRank - 1].floor == floor ) {
                return; 
            } 

            ranks[existRank - 1].floor = floor;
            ranks[existRank - 1].time = now;
        }else {
            if( ranks.length < 3 ) {
                ranks.push(userRank); 
            }else {
                var lastRank = ranks[2]; 
                if( lastRank.floor >= userRank.floor ) {
                    return; 
                }
                
                ranks.pop();
                ranks.push(userRank);
            }
        }

        ranks = ranks.sort(function(a, b) { return b.floor - a.floor;});
        this.ranks = ranks.sort(function(a, b) { return ((a.floor == b.floor) ? (a.time - b.time) : 0); })
        this.save();
    },
}

exports.update_tower_activity_rank = function(req, resp, onHandled) {
    do{
        var activitySchedule = findActivitySchedule('tower');
        if( !activitySchedule ) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var name = req.args.name || '';
        var headpic = req.args.headpic || '';
        var floor = Math.floor(req.args.floor);
        
        gTowerActivityRank.update(req.uid, name, headpic, floor);
    }while(false);

    onHandled();
}

exports.get_tower_activity_rank = function(req, resp, onHandled) {

    var activitySchedule = findActivitySchedule('tower');
    if( activitySchedule ) {
        var name = req.args.name || '';
        var headpic = req.args.headpic || '';
        var floor = Math.floor(req.args.floor);
        
        gTowerActivityRank.update(req.uid, name, headpic, floor);
    }


    resp.data.ranks = gTowerActivityRank.ranks;
    onHandled();
}

exports.get_tower_activity_rank_reward = function(req, resp, onHandled) {
    var uid = req.uid;
    var haveReward = false;
    var ranks = gTowerActivityRank.ranks;
    var rewardRank = 0;
    for( var i = 0, len = ranks.length; i < len; i++ ) {
        var rank = ranks[i];
        if( (rank.uid == uid) && !(rank.got) ) {
            rank.got = 1;
            rewardRank = i + 1;
            haveReward = true;
            break;
        }
    }

    if( !haveReward ) {
        resp.data.update = 1;
    }else {
        resp.data.awards = [gConfAvTowerRank[rewardRank].Award1];
        gTowerActivityRank.save();
    }

    resp.data.ranks = ranks;

    onHandled();
}

function LevelRank(){
    this.ranks = null;
}

LevelRank.create = function(){
    var ranks = [
        /*{'uid':0, 'name':'', 'headpic':'', 'level':0, 'got' :0},*/
    ];
    gDBWorld.insert({_id:'level_rank', rank:ranks}, function(err, result){}); 
}

LevelRank.prototype = {
    init : function(callback) {
        // 读取排行榜数据
        gDBWorld.findOne({_id: 'level_rank'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    save : function() {
        gDBWorld.save({_id: 'level_rank', rank: this.ranks}, function(err, result){});
    },

    update : function(uid, name, headpic, level) {
        var now = common.getTime();
        var userRank = {
            'uid' : uid, 
            'name' :name,
            'headpic':headpic,
            'level': level,
            'got':0,
            'time':now,
        };
        
        var ranks = this.ranks;
        var existRank = 0;
        for( var i=0, len = ranks.length; i<len; i++ ) {
            var rank = ranks[i];
            if( !rank.time ) {
                rank.time = now; 
            }

            if( rank.uid == uid ) {
                existRank = i+1;
            }
        }
        
        if( existRank ) {
            if( ranks[existRank - 1].level == level ) {
                return; 
            }

            ranks[existRank - 1].level = level;
            ranks[existRank - 1].time = now;
        }else {
            if( ranks.length < 3 ) {
                ranks.push(userRank); 
            }else {
                var lastRank = ranks[2]; 
                if( lastRank.level >= userRank.level ) {
                    return; 
                }

                ranks.pop();
                ranks.push(userRank);
            }
        }
        
        ranks = ranks.sort(function(a, b) { return b.level - a.level;});
        this.ranks = ranks.sort(function(a, b) { return ((a.level == b.level) ? (a.time - b.time) : 0); })
        this.save();
    },
}

exports.update_level= function(req, resp, onHandled) {
    do{
        var activitySchedule = findActivitySchedule('levelrank');
        if( !activitySchedule ) {
            resp.code = 1; resp.desc = 'not open'; break;
        }

        var name = req.args.name || '';
        var headpic = req.args.headpic || '';
        var level = Math.floor(req.args.level);

        gLevelRank.update(req.uid, name, headpic, level);
    }while(false);

    onHandled();
}

exports.get_level_rank = function(req, resp, onHandled) {

    var activitySchedule = findActivitySchedule('levelrank');
    if( activitySchedule ) {
        var name = req.args.name || '';
        var headpic = req.args.headpic || '';
        var level = Math.floor(req.args.level);

        gLevelRank.update(req.uid, name, headpic, level);
    }


    resp.data.ranks = gLevelRank.ranks;
    onHandled();
}

exports.get_level_rank_reward = function(req, resp, onHandled) {
    var uid = req.uid;
    var haveReward = false; 
    var ranks = gLevelRank.ranks; 
    var rewardRank = 0; 
    for( var i = 0, len = ranks.length; i < len; i++ ) { 
        var rank = ranks[i]; 
        if( (rank.uid == uid) && !(rank.got) ) { 
            rank.got = 1; 
            rewardRank = i + 1; 
            haveReward = true; 
            break; 
        } 
    }   
    
    if( !haveReward ) { 
        resp.data.update = 1; 
    }else { 
        resp.data.awards = [gConfAvLevelRank[rewardRank].Award1]; 
        gLevelRank.save(); 
    } 

    resp.data.ranks = gLevelRank.ranks;

    onHandled();
}

function FightForceRank(){
    this.ranks = null;
}

FightForceRank.create = function(){
    var ranks = [
        /*{'uid':0, 'name':'', 'headpic':'', 'fight_force':0, 'got':0},*/
    ];
    gDBWorld.insert({_id:'fight_force_rank', rank:ranks}, function(err, result){}); 
}

FightForceRank.prototype = {
    init : function(callback) {
        // 读取排行榜数据
        gDBWorld.findOne({_id: 'fight_force_rank'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                callback && callback(true);
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    save : function() {
        gDBWorld.save({_id: 'fight_force_rank', rank: this.ranks}, function(err, result){});
    },

    update : function(uid, name, headpic, fightForce) {
        var now = common.getTime();
        var userRank = {
            'uid' : uid, 
            'name' :name,
            'headpic':headpic,
            'fight_force':fightForce,
            'got':0,
            'time':now,
        };
        
        var ranks = this.ranks;
        var existRank = 0;
        for( var i=0, len = ranks.length; i<len; i++ ) {
            var rank = ranks[i];
            if( !rank.time ) {
                rank.time = now; 
            }

            if( rank.uid == uid ) {
                existRank = i+1;
            }
        }

        if( existRank ) {
            if( ranks[existRank - 1].fight_force == fightForce ) {
                return; 
            }

            ranks[existRank - 1].fight_force = fightForce;
            ranks[existRank - 1].time = now;
        }else {
            if( ranks.length < 3 ) {
                ranks.push(userRank); 
            }else {
                
                var lastRank = ranks[2]; 
                if( lastRank.fight_force >= fightForce ) {
                    return; 
                }

                ranks.pop();
                ranks.push(userRank);
            }
        }
        
        ranks = ranks.sort(function(a, b) { return b.fight_force - a.fight_force;});
        this.ranks = ranks.sort(function(a, b) { return ((a.fight_force == b.fight_force) ? (a.time - b.time) : 0); })
        this.save();
    },
}

exports.get_fight_force_rank = function(req, resp, onHandled) {
    do{
        var activitySchedule = findActivitySchedule('fightforce');
        if( activitySchedule ) {
            var name = req.args.name || '';
            var headpic = req.args.headpic || '';
            var fightForce = Math.floor(req.args.fight_force);
            
            gFightForceRank.update(req.uid, name, headpic, fightForce);
        }

        resp.data.ranks = gFightForceRank.ranks;

    }while(false);

    onHandled();
}

exports.get_fight_force_rank_reward = function(req, resp, onHandled) {
    var uid = req.uid;
    var haveReward = false;
    var ranks = gFightForceRank.ranks;
    var rewardRank = 0;
    for( var i = 0, len = ranks.length; i < len; i++ ) {
        var rank = ranks[i];
        if( (rank.uid == uid) && !(rank.got) ) {
            rank.got = 1;
            rewardRank = i + 1;
            haveReward = true;
            break;
        }
    }

    if( !haveReward ) {
        resp.data.update = 1;
    }else {
        resp.data.awards = [gConfAvFightForceRank[rewardRank].Award1];
        gFightForceRank.save();
    }

    resp.data.ranks = ranks;

    onHandled();
}

// 新千重楼
function TowerRank2(){
    this.ranks = null;
}

TowerRank2.create = function(){
    var ranks = {
        /*towerId : [
            {'uid':0, 'name':'', 'headpic':'', 'floor':0, 'fight_force':0, 'time':0},
        ],*/
    };

    gDBWorld.insert({_id:'tower_rank2', rank:ranks}, function(err, result){}); 
}

TowerRank2.prototype = {
    init : function(callback) {
        // 读取排行榜数据
        gDBWorld.findOne({_id: 'tower_rank2'}, {}, function(err, doc){
            if( doc ) {
                this.ranks = doc.rank;
                if( Object.keys(this.ranks) > 0 ) {
                    callback && callback(true);
                    return;
                }

                gDBWorld.findOne({_id: 'tower_rank'}, {}, function(err, doc){
                    if( !doc ) {
                        callback && callback(false);
                    }

                    var oldTowerRanks = doc.rank;
                    // 将旧的千重楼数据复制过来
                    if( !this.ranks[1] ) {
                        this.ranks[1] = [];
                        var now = common.getTime();
                        for( var i = 1; i <= 3; i++ ) {
                            var rank = oldTowerRanks[i];
                            var userRank = {
                                'uid' : rank.uid, 
                                'name' :rank.name,
                                'headpic':rank.headpic,
                                'floor':rank.floor,
                                'fight_force':rank.fight_force,
                                'time' : now, 
                            };

                            this.ranks[1].push(userRank);
                        }
                    }
                    callback && callback(true);
                }.bind(this));
            }else{
                callback && callback(false);
            }
        }.bind(this));
    },

    save : function() {
        gDBWorld.save({_id: 'tower_rank2', rank: this.ranks}, function(err, result){});
    },

    update : function(towerId, uid, name, headpic, floor, fightForce) {
        if( !(towerId in this.ranks) ) {
            this.ranks[towerId] = [];
        }

        var now = common.getTime();
        var userRank = {
            'uid' : uid, 
            'name' :name,
            'headpic':headpic,
            'floor':floor,
            'fight_force':fightForce,
            'time' : now, 
        };
        
        var ranks = this.ranks[towerId];
        var existRank = 0;
        for( var i=0, len = ranks.length; i<len; i++ ) {
            var rank = ranks[i];
            if( !rank.time ) {
                rank.time = now; 
            }

            if( rank.uid == uid ) {
                existRank = i+1;
            }
        }
        
        if( existRank ) {
            if( ranks[existRank - 1].floor == floor ) {
                return; 
            }
        
            ranks[existRank - 1].name = name;
            ranks[existRank - 1].headpic = headpic;
            ranks[existRank - 1].fight_force = fightForce;
            ranks[existRank - 1].floor = floor;
            ranks[existRank - 1].time = now;
        }else {
            if( ranks.length < 3 ) {
                ranks.push(userRank);
            }else {
                var lastRank = ranks[2]; 
                if( lastRank.floor >= userRank.floor ) {
                    return; 
                }
                
                ranks.pop();
                ranks.push(userRank);
            }
        }

        ranks = ranks.sort(function(a, b) { return b.floor - a.floor;});
        this.ranks[towerId] = ranks.sort(function(a, b) { return ((a.floor == b.floor) ? (a.time - b.time) : 0); })
        this.save();
    },
}

exports.update_tower = function(req, resp, onHandled) {
    do{

        if( isNaN(req.args.floor) || isNaN(req.args.fight_force) ) {
            resp.code = 1; resp.desc='no valid args'; break;
        }

        var name = req.args.name || '';
        var headpic = req.args.headpic || '';
        var floor = Math.floor(req.args.floor);
        var fightForce = Math.floor(req.args.fight_force);
        var towerId = Math.floor(req.args.tower);
        
        gTowerRank2.update(towerId, req.uid, name, headpic, floor, fightForce);
    }while(false);

    onHandled();
}

exports.get_tower = function(req, resp, onHandled) {

    resp.data.ranks = gTowerRank2.ranks;
    onHandled();
}


exports.Rank = Rank;
exports.TowerRank = TowerRank;
exports.TopOne2 = TopOne2;
exports.TowerActivityRank = TowerActivityRank;
exports.FightForceRank = FightForceRank;
exports.LevelRank = LevelRank;
exports.TowerRank2 = TowerRank2;
